//-----------------------------------------------
//    module name: m_InterruptFirst
//    author: LuYihua
//  
//    version: 1st version (2021-10-01)
//    description: 接收来自第一级流水的中断信号和异常信号，更新相应寄存器的值并给出中断（异常）处理程序的PC
//        
//
//
//-----------------------------------------------
`timescale 1ns / 1ps

module m_InterruptFirst(

    input  wire  [ 4:0] i_errFlag_5,                //interrupt signal（中断信号）
    input  wire  [ 4:0] i_intFlag_5,                //exception signal（异常信号）
                                                   
    input  wire  [31:0] i_curPC_32,                 //currentPC（当前指令PC）
    input  wire  [31:0] i_curInst_32,               //currentInstr（当前指令）
                                                   
    input  wire  [31:0] i_mtvecValue_32,            //MISP register value（MSIP寄存器值，MSIP寄存器为机器模式软件中断 等待寄存器，用以产生或者清除软件中断）
    input  wire  [31:0] i_mstatusValue_32,          //data input mevtc register （MTVEC寄存器值，MTVEC寄存器为机器模式异常入口基地址寄存器，定义进入异常的程序 PC 地址）
    input  wire  [31:0] i_mepcValue_32,             //data input mstatus register（MSTATUS寄存器为机器模式状态寄存器，该寄存器中的MIE域和MPIE域用于反应全局中断使能）   
    input  wire         i_holdflag_1,               //data input mepc register（MEPC寄存器值，MEPC寄存器为机器模式异常 PC 寄存器，该寄存器用于保存异常的返回地址）   
                                                   
    output wire  [31:0] o_newPC_32,                 //newPC（进入中断/异常后，下一条需要处理的程序所在的地址）
    output wire         o_EnNewPC_1,                //当前新PC的使能信号。用于控制当前输出的新PC是否有效
    
    output wire [128:0] o_intFToCsr_129

    );
    wire        w_EnNewCsr_1;               //当前新CSR寄存器值的使能信号。用于控制当前输出的新CSR是否有效
    wire [31:0] w_mcauseValue_32;  
    wire [31:0] w_mepcValue_32;
    wire [31:0] w_mtvalValue_32;
    wire [31:0] w_mstatusValue_32;
    
    assign o_intFToCsr_129 = {    w_EnNewCsr_1,     
                                w_mcauseValue_32,  
                                w_mepcValue_32,    
                                w_mtvalValue_32,   
                                w_mstatusValue_32  };    
                                
    wire        w_globalDisInterrupt;
    
    wire [4:0 ] w_errFlag_5;
    wire [4:0 ] w_intFlag_5;
    wire [31:0] w_mcauseErr_32;          //异常对应的mcause编码
    wire [31:0] w_mcauseInt_32;          //中断对应的mcause编码
    wire        w_isInEcallOrEbreak_1;  
    wire        w_isRet_1;               //需要从异常返回
    wire        w_modEn_1;
    
    assign w_isRet_1              = i_errFlag_5 == `SYS_ENVIRONMENT_RET ;
    assign w_isInEcallOrEbreak_1  = w_mcauseValue_32 == 32'h00000003 | w_mcauseValue_32 == 32'h0000000B;
    //??????????????  
    assign w_globalDisInterrupt   =  i_holdflag_1 | ~i_mstatusValue_32[3] ; // & i_secondflow_err_1; 第二级异常视为全局关中断
    //assign w_regWriteEnable = ~w_globalDisInterrupt;      //优先由第二级中断写PC与CSR

    assign o_EnNewPC_1      = w_modEn_1 | w_isRet_1 | w_isInEcallOrEbreak_1;
    assign w_EnNewCsr_1     = w_modEn_1 | w_isRet_1 & ~w_isInEcallOrEbreak_1;
    assign w_modEn_1= (|w_errFlag_5) | (|w_intFlag_5);
 //-----{mcauseValue}begin 
    assign w_errFlag_5      = i_errFlag_5 != `SYS_ENVIRONMENT_CALL & w_globalDisInterrupt ? 5'b00000:  i_errFlag_5 ;
    assign w_intFlag_5      = i_errFlag_5 != `SYS_ENVIRONMENT_CALL & w_globalDisInterrupt ? 5'b00000:  i_intFlag_5 ;
        
    assign w_mcauseErr_32   = (w_errFlag_5 == `IF_VISIT_ERR                ) ? 32'h00000001 : //Value access error
                              (w_errFlag_5 == `SYS_BREAKPOINT              ) ? 32'h00000003 : //breakpoint
                              (w_errFlag_5 == `SYS_ENVIRONMENT_CALL        ) ? 32'h0000000B : 
                                                                               32'hFFFFFFFF ; 
    
    assign w_mcauseInt_32   = (w_intFlag_5 == `SOFTWARE_INT  ) ? 32'h80000003 :                  //Software interrupt
                              (w_intFlag_5 == `TIMMER_INT    ) ? 32'h80000007 :                  //timer interrupt
                              (w_intFlag_5 == `SOFTWARE_EXT1 ) ? 32'h8000000F :                  //External interrupt     
                              (w_intFlag_5 == `SOFTWARE_EXT2 ) ? 32'h80000010 :                  //External interrupt     
                              (w_intFlag_5 == `SOFTWARE_EXT3 ) ? 32'h80000011 :                  //External interrupt                       
                                                                 32'h00000000 ;
                                                                
    assign w_mcauseValue_32 = (~|w_errFlag_5) ? w_mcauseInt_32 : w_mcauseErr_32;

//-----{mcauseValue}end

//-----{newPc}begin 
    wire [ 1:0] w_mode_2;
    wire [31:0] w_NewPcMode0_32;
    wire [31:0] w_NewPcMode1_32;
    wire [ 3:0] w_cause_4;
    assign w_mode_2        =  i_mtvecValue_32[1:0];
    assign w_cause_4       = (w_mcauseValue_32 == 32'h80000003 ) ? 5'd3  :         // SOFTWARE_INT 
                             (w_mcauseValue_32 == 32'h80000007 ) ? 5'd7  :         // TIMMER_INT   
                             (w_mcauseValue_32 == 32'h8000000F ) ? 5'd16 :         //External interrupt     
                             (w_mcauseValue_32 == 32'h80000010 ) ? 5'd17 :         //External interrupt     
                             (w_mcauseValue_32 == 32'h80000011 ) ? 5'd18 :         //External interrupt  
                                                                   5'd0;   
                              
    assign w_NewPcMode0_32 = {i_mtvecValue_32[31:2],2'b0};
    assign w_NewPcMode1_32 = (w_mcauseValue_32[31]) ? {i_mtvecValue_32[31:2],2'b0}+{28'b0,w_cause_4}<<2 :{i_mtvecValue_32[31:2],2'b0};                    
    
    assign o_newPC_32      = (w_isRet_1             ) ? i_mepcValue_32  :     //机器模式异常返回处理
                             (w_isInEcallOrEbreak_1 ) ? w_NewPcMode0_32 :
                             (w_mode_2 == `MODE_0   ) ? w_NewPcMode0_32 :
                             (w_mode_2 == `MODE_1   ) ? w_NewPcMode1_32 :
                                                                            32'b0;
//-----{newPc}end
//-----{newCsr}begin 
    assign w_mepcValue_32  =  i_curPC_32;
    assign w_mtvalValue_32 = w_isRet_1 & ~w_isInEcallOrEbreak_1 ? i_curInst_32:32'b0;
    
    assign w_mstatusValue_32[31:8] = i_mstatusValue_32[31:8] ;
    assign w_mstatusValue_32[6:4]  = i_mstatusValue_32[6:4]  ;
    assign w_mstatusValue_32[2:0]  = i_mstatusValue_32[2:0]  ;
    
    assign w_mstatusValue_32[7] = w_isRet_1 & ~w_isInEcallOrEbreak_1 ? 1'b1:i_mstatusValue_32[3];    //MPIE
    assign w_mstatusValue_32[3] = w_isRet_1 & ~w_isInEcallOrEbreak_1 ? 1'b1:1'b0;                    //shut down MIE
//-----{newCsr}end
endmodule
